package com.hexb.smh.service.impl;

import com.hexb.core.exception.BusinessException;
import com.hexb.core.model.BaseErrorCodes;
import com.hexb.core.utils.Assert;
import com.hexb.smh.entity.EvaluateLevel;
import com.hexb.smh.errors.ErrorCodes;
import com.hexb.smh.mapper.EvaluateLevelMapper;
import com.hexb.smh.service.IEvaluateLevelService;
import io.swagger.models.auth.In;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author : hexb
 */
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class EvaluateLevelService implements IEvaluateLevelService {

    @NonNull
    private final EvaluateLevelMapper evaluateLevelMapper;

    @Override
    public int save(EvaluateLevel el) {
        Assert.isNull(el, BaseErrorCodes.PARAMETER_IS_NULL);
        Assert.isTrue(el.getValueFrom() == null && el.getValueFrom() == null, ErrorCodes.SCORE_MUST_NOT_BOTH_NULL);
        checkNameDuplicate(el.getLevelName(), null);
        checkValueDuplicate(el.getValueFrom(), null, null);
        checkValueDuplicate(null, el.getValueTo(), null);
        checkInclude(el);
        try {
            return evaluateLevelMapper.save(el);
        } catch (DuplicateKeyException e) {
            throw new BusinessException(ErrorCodes.DUPLICATE_SCORE_OR_NAME);
        }
    }

    @Override
    public int update(EvaluateLevel el) {
        Assert.isNull(el, BaseErrorCodes.PARAMETER_IS_NULL);
        Assert.isNull(el.getId(), BaseErrorCodes.PARAMETER_IS_NULL);
        Assert.isTrue(el.getValueFrom() == null && el.getValueTo() == null, ErrorCodes.SCORE_MUST_NOT_BOTH_NULL);

        checkNameDuplicate(el.getLevelName(), el.getId());
        checkValueDuplicate(el.getValueFrom(), null, el.getId());
        checkValueDuplicate(null, el.getValueTo(), el.getId());
        checkInclude(el);
        try {
            return evaluateLevelMapper.update(el);
        } catch (DuplicateKeyException e) {
            throw new BusinessException(ErrorCodes.DUPLICATE_SCORE_OR_NAME);
        }
    }

    @Override
    public EvaluateLevel selectByValue(BigDecimal value) {
        return evaluateLevelMapper.selectByValue(value);
    }

    @Override
    public List<EvaluateLevel> selectAll() {
        return evaluateLevelMapper.selectAll();
    }

    @Override
    public int delete(Integer id) {
        Assert.isNull(id, BaseErrorCodes.PARAMETER_IS_NULL);
        return evaluateLevelMapper.delete(id);
    }

    @Override
    public int deleteBatch(Integer[] ids) {
        Assert.isEmpty(ids, BaseErrorCodes.PARAMETER_IS_NULL);
        return evaluateLevelMapper.deleteBatch(ids);
    }

    @Override
    public Boolean checkName(String name, Integer id) {
        try {
            this.checkNameDuplicate(name, id);
            return true;
        } catch (Exception e) {
            log.debug("名称检查重复");
        }
        return false;
    }

    private void checkNameDuplicate(String name, Integer id) {
        EvaluateLevel ln = evaluateLevelMapper.selectByName(name, id);
        Assert.notNull(ln, ErrorCodes.DUPLICATE_LEVEL_NAME, name);
    }

    private void checkValueDuplicate(BigDecimal valueFrom, BigDecimal valueTo, Integer id) {
        if (valueFrom == null && valueTo == null) return;
        EvaluateLevel vf = evaluateLevelMapper.selectByValueCheck(valueFrom, valueTo, id);
        Assert.notNull(vf, ErrorCodes.DUPLICATE_SCORE,
                valueFrom == null ? valueTo : valueFrom,
                vf != null ? vf.getLevelName() : "");
    }

    private void checkInclude(EvaluateLevel el) {
        List<EvaluateLevel> includes = evaluateLevelMapper.selectIncludes(el.getValueFrom(), el.getValueTo(), el.getId());
        if (null != includes && !includes.isEmpty()) {
            List<String> list = includes.stream().map(EvaluateLevel::format).collect(Collectors.toList());
            String str = String.join(",", list);
            throw new BusinessException(ErrorCodes.INCLUDE_SCORE, el.getLeftValue(), el.getRightValue(), str);
        }
    }
}
